﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Diagrams;
using Simulator;

namespace DiagramParser
{
    public class DiagramError
    {
        /// <summary>
        /// Текстовое описание ошибки (для пользователя)
        /// </summary>
        public string Description;
        /// <summary>
        /// Идентификатор объекта, вызвавшего ошибку
        /// </summary>
        public string SenderName;
        public DiagramError(string message, string object_name)
        {
            Description = message;
            SenderName = object_name;
        }

        public DiagramError() {
            // TODO: Complete member initialization
        }
    }
    public class DiagramToKernelParser
    {
        /// <summary>
        /// Создает экземпляр класса-наследника типа Block
        /// </summary>
        /// <param name="DiagramBlockType">Строка типов из диаграммы</param>
        /// <returns></returns>
        public static Block TranslateBlockType(string DiagramBlockType)
        {
            Block b = null;
            switch (DiagramBlockType)
            {
                case "ActivityBlock":
                    b = new Simulator.Action();
                    break;
                case "ResourceBlock":
                    b = new Resource();
                    break;
                case "SynchroBlock":
                    b = new Sync();
                    break;
                case "ParallelBlock":
                    b = new Parall();
                    break;
                case "SourceBlock":
                    b = new Source();
                    break;
                case "SinkBlock":
                    b = new Sink();
                    break;
                case "DecisionBlock":
                    b = new Decision();
                    break;
                case "EntityCollectorBlock":
                    b = new Collector();
                    break;
                case "ExternalResourceBlock":
                    //добавить блок внешнего ресурса!
                    break;
                default:
                    //добавить код
                    break;
            }
            return b;
        }
        //находит связи для блока EntityCollector
        protected static Figure FindCollectorNext(ComplexFigure entityCollector, Diagram diagram)
        {
            Figure To = null;
            LineFigure line;
            foreach(Figure figure in diagram.figures)
                if (figure is LineFigure)
                {
                    line = figure as LineFigure;
                    if (line.From.OwnerFigure == entityCollector)
                    {
                        if (line.To != null)
                            To = line.To.OwnerFigure;
                        break;
                    }
                }
            return To;
        }
        /// <summary>
        /// Фунция соединения двух блоков
        /// </summary>
        /// <returns>Если соединение произошло без ошибок, возвращает true</returns>
        public static bool ConnectBlocks(Diagram diagram, ref List<Block> blocks, string NameFrom, string NameTo)
        {
            return false;
        }
        /// <summary>
        /// Функция устанавливает связи между всеми блоками. Предполагается вызывать перед запуском симуляции
        /// </summary>
        /// <param name="diagram">Диаграмма</param>
        /// <param name="blocks">Список блоков, соответствующих блокам диаграммы</param>
        public static List<DiagramError> SetLinks(Diagram diagram, ref List<Block> blocks)
        {
            List<DiagramError> errors = new List<DiagramError>(); 

            CheckSyntax(blocks, ref errors);
            return errors;
        }
        /// <summary>
        /// Функция проверяет синтаксис диаграммы
        /// </summary>
        /// <param name="blocks">Список связанных блоков, образующих диаграмму</param>
        private static void CheckSyntax(List<Block> blocks, ref List<DiagramError> errors)
        {
            int sourceCtr = 0, sinkCtr = 0;
            for (int i = 0; i < blocks.Count; i++)
            {
                Block b = blocks[i];
                if(b is Sink || b is Simulator.Action || b is Decision || b is Parall)
                    if (b.Prev == null)
                        errors.Add(new DiagramError("Вход блока №" + (i + 1).ToString() + " не подключен.", b.Name));
                if (b is Source || b is Simulator.Action || b is Collector || b is Sync)
                    if (b.Next == null)
                        errors.Add(new DiagramError("Выход блока №" + (i + 1).ToString() + " не подключен.", b.Name));
                if (b is Source)
                    sourceCtr++;
                if (b is Sink)
                    sinkCtr++;
                if (b is Simulator.Action)
                {
                    if((b as Simulator.Action).Resources.Count == 0)
                        errors.Add(new DiagramError("Блок №" + (i + 1).ToString() + " (процедура) не связан с ресурсами.", b.Name));
                }
                if (b is Decision)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        if((b as Decision).Next[j] == null && (b as Decision).PortMap[j] != 'h')
                            errors.Add(new DiagramError("Активный выход (" + NumToDecisionPort(j) + ") блока  №" + (i + 1).ToString() + " (принятия решения) не подключен.", b.Name));
                    }
                }
                if (b is Collector)
                {
                    bool connect = false;
                    for (int j = 0; j < 3; j++)
                        if ((b as Collector).Prev[j] != null)
                            connect = true;
                    if(!connect)
                        errors.Add(new DiagramError("Ни один из входов блока №" + (i + 1).ToString() + " не подключен.", b.Name));
                }
                if (b is Parall)
                {
                    if((b as Parall).Next == null || (b as Parall).Next2 == null)
                        errors.Add(new DiagramError("Не все выходы блока №" + (i + 1).ToString() + " подключены.", b.Name));
                }
                if (b is Sync)
                {
                    if ((b as Sync).Prev == null || (b as Sync).Prev2 == null)
                        errors.Add(new DiagramError("Не все входы блока №" + (i + 1).ToString() + " подключены.", b.Name));
                }
            }
            if (blocks.Count > 0)
            {
                if (sourceCtr == 0)
                    errors.Add(new DiagramError("На диаграмме нет источника сущностей.", ""));
                if (sinkCtr == 0)
                    errors.Add(new DiagramError("На диаграмме нет стока сущностей.", ""));
            }else
                errors.Add(new DiagramError("На диаграмме нет объектов.", ""));
        }
        static string NumToDecisionPort(int k)
        {
            if (k == 0)
                return "верхний";
            if (k == 1)
                return "правый";
            return "нижний";
        }
    }
}
